package com.rankeiot.developer.modules;

import com.rankeiot.core.util.castor.BooleanCastor;
import com.rankeiot.platform.service.CacheDataService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.sagacity.sqltoy.callback.StreamResultHandler;
import org.sagacity.sqltoy.config.model.Translate;
import org.sagacity.sqltoy.dao.LightDao;
import org.sagacity.sqltoy.model.Page;
import org.sagacity.sqltoy.model.QueryExecutor;
import org.springframework.stereotype.Component;
import org.ssssssss.magicapi.core.annotation.MagicModule;
import org.ssssssss.magicapi.core.model.Options;
import org.ssssssss.magicapi.datasource.model.MagicDynamicDataSource;
import org.ssssssss.magicapi.modules.DynamicModule;
import org.ssssssss.magicapi.modules.db.SQLModule;
import org.ssssssss.magicapi.modules.db.Transaction;
import org.ssssssss.script.MagicScriptContext;
import org.ssssssss.script.annotation.Comment;
import org.ssssssss.script.functions.DynamicAttribute;
import org.ssssssss.script.runtime.RuntimeContext;

import java.beans.Transient;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;

@Component
@MagicModule("dao")
@RequiredArgsConstructor
public class DaoModule implements DynamicAttribute<DaoModule, DaoModule>, DynamicModule<DaoModule> {
    final private LightDao dao;
    final private  MagicDynamicDataSource dynamicDataSource;
    private MagicDynamicDataSource.DataSourceNode dataSourceNode;

    private int maxPageSize=200;

    @Transient
    @Comment("设置分页最大条数,小于1为不限制")
    public void setMaxPageSize(int maxPageSize){
        this.maxPageSize=maxPageSize;
    }


    @Transient
    public void setDataSourceNode(MagicDynamicDataSource.DataSourceNode dataSourceNode) {
        this.dataSourceNode = dataSourceNode;
    }

    /**
     * 数据源切换
     */
    @Override
    @Transient
    public DaoModule getDynamicAttribute(String key) {
        DaoModule daoModule = new DaoModule(dao,dynamicDataSource);
        if (key == null) {
            daoModule.setDataSourceNode(dynamicDataSource.getDataSource());
        } else {
            daoModule.setDataSourceNode(dynamicDataSource.getDataSource(key));
        }
        return daoModule;
    }
    @Transient
    @Override
    public DaoModule getDynamicModule(MagicScriptContext context) {
        String dataSourceKey = context.getString(Options.DEFAULT_DATA_SOURCE.getValue());
        if (StringUtils.isEmpty(dataSourceKey)) return this;
        DaoModule daoModule = new DaoModule(dao,dynamicDataSource);
        daoModule.setDataSourceNode(dynamicDataSource.getDataSource(dataSourceKey));
        return daoModule;
    }
    @Comment("开启事务，并在回调中处理")
    public Object transaction(@Comment(name = "function", value = "回调函数，如：()=>{....}") Function<?, ?> function) {
        Transaction transaction = this.transaction();

        try {
            Object val = function.apply(null);
            transaction.commit();
            return val;
        } catch (Throwable var4) {
            transaction.rollback();
            throw var4;
        }
    }

    @Comment("开启事务，返回事务对象")
    public Transaction transaction() {
        return new Transaction(this.dataSourceNode.getDataSourceTransactionManager());
    }

    @Comment("执行分页查询")
    public Page page(RuntimeContext context, @Comment(name = "sqlOrId", value = "查询语句") String sqlOrId) {
        return dao.findPage(getPage(context), sqlOrId, context.getVarMap(), Map.class);
    }

    @Comment("执行分页查询")
    public Page page(RuntimeContext context,@Comment(name = "query",value = "查询对象") QueryExecutor query) {
        return dao.findPageByQuery(getPage(context), query).getPageResult();
    }

    @Comment("通过query查询，返回List类型结果")
    public List find(@Comment(name = "query",value = "查询对象")QueryExecutor query) {
        return dao.findByQuery(query).getRows();
    }
    @Comment("查询SQL，返回List类型结果")
    public List<Map> find(RuntimeContext context, @Comment(name = "sqlOrId",value = "`SQL`语句或`xmlId`") String sqlOrId) {
        return dao.find(sqlOrId,context.getVarMap(), Map.class);
    }
    @Comment("流式获取查询结果")
    public void fetchStream(@Comment(name = "query",value = "查询对象")QueryExecutor query,@Comment(name = "resultHandler", value = "查询回调函数，如：(row,index)=>{....}") StreamResultHandler resultHandler){
        dao.fetchStream(query,resultHandler);
    }

    @Comment("执行update操作，并传入变量信息，返回受影响行数")
    public long batchUpdate(@Comment(name = "sqlOrId",value = "`SQL`语句或`xmlId`") String sqlOrId,@Comment(name = "dataSet",value = "支持List<List>、List<Object[]>(sql中?传参) ;List<VO>、List<Map>形式(sql中:paramName传参)") List dataSet){
       return dao.batchUpdate(sqlOrId,dataSet);
    }
    @Comment("执行sql操作，返回受影响行数")
    public long execute(RuntimeContext context,@Comment(name = "sqlOrId",value = "`SQL`语句或`xmlId`") String sqlOrId){
        return dao.executeSql(sqlOrId,context.getVarMap());
    }
    @Comment("通过map传参模式获取单条对象记录")
    public Map findOne(RuntimeContext context,@Comment(name = "sqlOrId",value = "`SQL`语句或`xmlId`") String sqlOrId){
      return  dao.findOne(sqlOrId,context.getVarMap(), Map.class);
    }
    @Comment("获取查询结果的第一条、第一列的值，一般用select max(x) from 等")
    public Object getValue(RuntimeContext context,@Comment(name = "sqlOrId",value = "`SQL`语句或`xmlId`") String sqlOrId){
        return dao.getValue(sqlOrId,context.getVarMap());
    }
    @Comment("获取统计数量")
    public long count(RuntimeContext context,@Comment(name = "sqlOrId",value = "`SQL`语句或`xmlId`") String sqlOrId){
        return dao.getCount(sqlOrId,context.getVarMap());
    }

    @Comment("获取查询对象")
    public QueryExecutor query(RuntimeContext context, String sqlOrId) {
        return new QueryExecutor(sqlOrId, context.getVarMap()).resultType(Map.class);
    }
    @Comment("获取翻译对象")
    public Translate translate(@Comment(name = "cacheName",value = "缓存名")String cacheName,@Comment(name = "cacheType",value = "缓存类型")String cacheType,@Comment(name = "column",value = "翻译列")String column){
        return new Translate(cacheName).setCacheType(cacheType).setColumn(column);
    }
    @Comment("获取分页对象")
    public Page getPage(RuntimeContext context) {

        long pageNo = NumberUtils.toLong(Objects.toString(context.eval("pageNo"), (String) null), 1);
        int pageSize = NumberUtils.toInt(Objects.toString(context.eval("pageSize"), (String) null), 10);
        boolean skipQueryCount = BooleanCastor.instance.cast(Objects.toString(context.eval("skipQueryCount")));

        pageSize=Math.max(1,pageSize);
        if(maxPageSize>0){
            pageSize=Math.min(pageSize,maxPageSize);
        }
        pageNo=Math.max(1,pageNo);
        Page page = new Page(pageSize, pageNo);
        page.setSkipQueryCount(skipQueryCount);
        return page;
    }

}
